home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / ACQUISITION.REF < prev    next >
Encoding:
Text File  |  2000-02-16  |  10.9 KB  |  311 lines

  1. <h1>Acquisition</h1>
  2. <p>  <a href="COPYRIGHT.html">Copyright (C) 1996-1998, Digital Creations</a>.</p>
  3.  
  4. <p>  Acquisition <a href="#1">[1]</a> is a mechanism that allows objects to obtain
  5.   attributes from their environment.  It is similar to inheritence,
  6.   except that, rather than traversing an inheritence hierarchy
  7.   to obtain attributes, a containment hierarchy is traversed.</p>
  8.  
  9. <p>  The <a href="ExtensionClass.html">ExtensionClass</a>. release includes mix-in
  10.   extension base classes that can be used to add acquisition as a
  11.   feature to extension subclasses.  These mix-in classes use the
  12.   context-wrapping feature of ExtensionClasses to implement
  13.   acquisition. Consider the following example:</p>
  14. <PRE>
  15.     import ExtensionClass, Acquisition
  16.  
  17.     class C(ExtensionClass.Base):
  18.       color='red'
  19.  
  20.     class A(Acquisition.Implicit):
  21.  
  22.       def report(self):
  23.         print self.color
  24.  
  25.     a=A()
  26.     c=C()
  27.     c.a=A()
  28.  
  29.     c.a.report() # prints 'red'
  30.  
  31.     d=C()
  32.     d.color='green'
  33.     d.a=a
  34.  
  35.     d.a.report() # prints 'green'
  36.  
  37.     a.report() # raises an attribute error
  38.  
  39. </PRE>
  40.  
  41. <p>  The class <code>A</code> inherits acquisition behavior from
  42.   <code>Acquisition.Implicit</code>.  The object, <code>a</code>, "has" the color of
  43.   objects <code>c</code> and <code>d</code> when it is accessed through them, but it
  44.   has no color by itself.  The object <code>a</code> obtains attributes
  45.   from it's environment, where it's environment is defined by
  46.   the access path used to reach <code>a</code>.</p>
  47.  
  48. <h2>Acquisition wrappers</h2>
  49. <p>    When an object that supports acquisition is accessed through
  50.     an extension class instance, a special object, called an
  51.     acquisition wrapper, is returned.  In the example above, the
  52.     expression <code>c.a</code> returns an acquisition wrapper that
  53.     contains references to both <code>c</code> and <code>a</code>.  It is this wrapper
  54.     that performs attribute lookup in <code>c</code> when an attribute
  55.     cannot be found in <code>a</code>.</p>
  56.  
  57. <p>    Aquisition wrappers provide access to the wrapped objects
  58.     through the attributes <code>aq_parent</code>, <code>aq_self</code>, <code>aq_base</code>.  
  59.     In the example above, the expressions:</p>
  60. <PRE>
  61.        'c.a.aq_parent is c'
  62.  
  63. </PRE>
  64.  
  65. <p>    and:</p>
  66. <PRE>
  67.        'c.a.aq_self is a'
  68.  
  69. </PRE>
  70.  
  71. <p>    both evaluate to true, but the expression:</p>
  72. <PRE>
  73.        'c.a is a'
  74.  
  75. </PRE>
  76.  
  77. <p>    evaluates to false, because the expression <code>c.a</code> evaluates
  78.     to an acquisition wrapper around <code>c</code> and <code>a</code>, not <code>a</code> itself.</p>
  79.  
  80. <p>    The attribute <code>aq_base</code> is similar to <code>aq_self</code>.  Wrappers may be
  81.     nested and <code>aq_self</code> may be a wrapped object.  The <code>aq_base</code>
  82.     attribute is the underlying object with all wrappers removed.</p>
  83.  
  84.  
  85. <h2>Acquisition Control</h2>
  86. <p>    Two styles of acquisition are supported in the current
  87.     ExtensionClass release, implicit and explicit aquisition.</p>
  88.  
  89. <h3>Implicit acquisition</h3>
  90. <p>      Implicit acquisition is so named because it searches for
  91.       attributes from the environment automatically whenever an
  92.       attribute cannot be obtained directly from an object or
  93.       through inheritence.</p>
  94.  
  95. <p>      An attribute may be implicitly acquired if it's name does
  96.       not begin with an underscore, <code>_</code>.</p>
  97.  
  98. <p>      To support implicit acquisition, an object should inherit
  99.       from the mix-in class <code>Acquisition.Implicit</code>.</p>
  100.  
  101.  
  102. <h3>Explicit Acquisition</h3>
  103. <p>      When explicit acquisition is used, attributes are not
  104.       automatically obtained from the environment.  Instead, the
  105.       method <code>aq_aquire</code> must be used, as in:</p>
  106. <PRE>
  107.         print c.a.aq_acquire('color')
  108.  
  109. </PRE>
  110.  
  111. <p>      To support explicit acquisition, an object should inherit
  112.       from the mix-in class <code>Acquisition.Explicit</code>.</p>
  113.  
  114.  
  115. <h3>Controlled Acquisition</h3>
  116. <p>      A class (or instance) can provide attribute by attribute control
  117.       over acquisition.  This is done by:</p>
  118.  
  119. <ul><li><p>subclassing from <code>Acquisition.Explicit</code>, and</p>
  120.  
  121.  
  122. <li><p>setting all attributes that should be acquired to the special
  123.         value: <code>Acquisition.Acquired</code>.  Setting an attribute to this
  124.         value also allows inherited attributes to be overridden with
  125.         acquired ones.</p>
  126. <p>        For example, in:</p>
  127. <PRE>
  128.           class C(Acquisition.Explicit):
  129.              id=1
  130.              secret=2
  131.              color=Acquisition.Acquired
  132.              __roles__=Acquisition.Acquired
  133.  
  134. </PRE>
  135.  
  136. <p>        The <em>only</em> attributes that are automatically acquired from
  137.         containing objects are <code>color</code>, and <code>__roles__</code>.  Note also
  138.         that the <code>__roles__</code> attribute is acquired even though it's
  139.         name begins with an underscore.  In fact, the special
  140.         <code>Acquisition.Acquired</code> value can be used in
  141.         <code>Acquisition.Implicit</code> objects to implicitly acquire selected
  142.         objects that smell like private objects.</p>
  143.  
  144.  
  145. </ul>
  146.  
  147. <h3>Filtered Acquisition</h3>
  148. <p>      The acquisition method, <code>aq_acquire</code>, accepts two optional
  149.       arguments. The first of the additional arguments is a
  150.       "filtering" function that is used when considering whether to
  151.       acquire an object.  The second of the additional arguments is an
  152.       object that is passed as extra data when calling the filtering
  153.       function and which defaults to <code>None</code>.</p>
  154.  
  155. <p>      The filter function is called with five arguments:</p>
  156.  
  157. <ul><li><p>The object that the <code>aq_acquire</code> method was called on,</p>
  158.  
  159.  
  160. <li><p>The object where an object was found,</p>
  161.  
  162.  
  163. <li><p>The name of the object, as passed to <code>aq_acquire</code>,</p>
  164.  
  165.  
  166. <li><p>The object found, and</p>
  167.  
  168.  
  169. <li><p>The extra data passed to <code>aq_acquire</code>.</p>
  170.  
  171. </ul>
  172. <p>      If the filter returns a true object that the object found is
  173.       returned, otherwise, the acquisition search continues.</p>
  174.  
  175. <p>      For example, in:</p>
  176. <PRE>
  177.         from Acquisition import Explicit
  178.  
  179.         class HandyForTesting:
  180.             def __init__(self, name): self.name=name
  181.             def __str__(self):
  182.                 return "%s(%s)" % (self.name, self.__class__.__name__)
  183.             __repr__=__str__
  184.  
  185.         class E(Explicit, HandyForTesting): pass
  186.  
  187.         class Nice(HandyForTesting):
  188.             isNice=1
  189.             def __str__(self):
  190.                 return HandyForTesting.__str__(self)+' and I am nice!'
  191.             __repr__=__str__
  192.  
  193.         a=E('a')
  194.         a.b=E('b')
  195.         a.b.c=E('c')
  196.         a.p=Nice('spam')
  197.         a.b.p=E('p')
  198.  
  199.         def find_nice(self, ancestor, name, object, extra):
  200.             return hasattr(object,'isNice') and object.isNice
  201.  
  202.         print a.b.c.aq_acquire('p', find_nice)
  203.  
  204. </PRE>
  205.  
  206. <p>      The filtered acquisition in the last line skips over the first
  207.       attribute it finds with the name <code>p</code>, because the attribute
  208.       doesn't satisfy the condition given in the filter. The output of
  209.       the last line is:</p>
  210. <PRE>
  211.         spam(Nice) and I am nice!
  212.  
  213. </PRE>
  214.  
  215.  
  216.  
  217. <h2>Acquisition and methods</h2>
  218. <p>    Python methods of objects that support acquisition can use
  219.     acquired attributes as in the <code>report</code> method of the first example
  220.     above.  When a Python method is called on an object that is
  221.     wrapped by an acquisition wrapper, the wrapper is passed to the
  222.     method as the first argument.  This rule also applies to
  223.     user-defined method types and to C methods defined in pure mix-in
  224.     classes.</p>
  225.  
  226. <p>    Unfortunately, C methods defined in extension base classes that
  227.     define their own data structures, cannot use aquired attributes at
  228.     this time.  This is because wrapper objects do not conform to the
  229.     data structures expected by these methods.</p>
  230.  
  231.  
  232. <h2>Acquiring Acquiring objects</h2>
  233. <p>    Consider the following example:</p>
  234. <PRE>
  235.       from Acquisition import Implicit
  236.  
  237.       class C(Implicit):
  238.           def __init__(self, name): self.name=name
  239.           def __str__(self):
  240.               return "%s(%s)" % (self.name, self.__class__.__name__)
  241.           __repr__=__str__
  242.  
  243.       a=C("a")
  244.       a.b=C("b")
  245.       a.b.pref="spam"
  246.       a.b.c=C("c")
  247.       a.b.c.color="red"
  248.       a.b.c.pref="eggs"
  249.       a.x=C("x")
  250.  
  251.       o=a.b.c.x
  252.  
  253. </PRE>
  254.  
  255. <p>    The expression <code>o.color</code> might be expected to return <code>"red"</code>. In
  256.     earlier versions of ExtensionClass, however, this expression
  257.     failed.  Acquired acquiring objects did not acquire from the
  258.     environment they were accessed in, because objects were only
  259.     wrapped when they were first found, and were not rewrapped as they
  260.     were passed down the acquisition tree.</p>
  261.  
  262. <p>    In the current release of ExtensionClass, the expression "o.color"
  263.     does indeed return <code>"red"</code>.</p>
  264.  
  265. <p>    When searching for an attribute in <code>o</code>, objects are searched in
  266.     the order <code>x</code>, <code>a</code>, <code>b</code>, <code>c</code>. So, for example, the expression,
  267.     <code>o.pref</code> returns <code>"spam"</code>, not <code>"eggs"</code>.  In earlier releases of
  268.     ExtensionClass, the attempt to get the <code>pref</code> attribute from <code>o</code>
  269.     would have failed.</p>
  270.  
  271. <p>    If desired, the current rules for looking up attributes in complex
  272.     expressions can best be understood through repeated application of
  273.     the <code>__of__</code> method:</p>
  274.  
  275. <dl><dt>    <code>a.x</code><dd><p><code>x.__of__(a)</code></p>
  276.  
  277.  
  278. <dt>    <code>a.b</code><dd><p><code>b.__of__(a)</code></p>
  279.  
  280.  
  281. <dt>    <code>a.b.x</code><dd><p><code>x.__of__(a).__of__(b.__of__(a))</code></p>
  282.  
  283.  
  284. <dt>    <code>a.b.c</code><dd><p><code>c.__of__(b.__of__(a))</code></p>
  285.  
  286.  
  287. <dt>    <code>a.b.c.x</code><dd><p><code>x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))</code></p>
  288.  
  289. </dl>
  290. <p>    and by keeping in mind that attribute lookup in a wrapper
  291.     is done by trying to lookup the attribute in the wrapped object
  292.     first and then in the parent object.  In the expressions above
  293.     involving the <code>__of__</code> method, lookup proceeds from left to right.</p>
  294.  
  295. <p>    Note that heuristics are used to avoid most of the repeated
  296.     lookups. For example, in the expression: <code>a.b.c.x.foo</code>, the object
  297.     <code>a</code> is searched no more than once, even though it is wrapped three
  298.     times.</p>
  299.  
  300.  
  301. <p>  <a name="1">[1]</a> Gil, J., Lorenz, D., 
  302.    <a href="http://www.bell-labs.com/people/cope/oopsla/Oopsla96TechnicalProgramAbstracts.html#GilLorenz">Environmental Acquisition--A New Inheritance-Like Abstraction Mechanism</a> 
  303.    OOPSLA '96 Proceedings, ACM SIG-PLAN, October, 1996</p>
  304.  
  305. <p>
  306. <TABLE BORDER=1 CELLPADDING=2>
  307. </TABLE></p>
  308.  
  309.  
  310.  
  311.